/*
 * @Author: liutongchao 1923236391@qq.com
 * @Date: 2023-04-26 17:07:46
 * @LastEditors: liutongchao 1923236391@qq.com
 * @LastEditTime: 2025-02-25 15:13:16
 * @FilePath: \greenbeeadmin\controllers\greenbee\utils\commonUtils.go
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
package utils

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/rand"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"math"
	"math/big"
	"os"
	"time"
)

// in_array 函数实现
func InArrayStr(s interface{}, d []string) bool {
	if len(d) > 0 {
		for _, v := range d {
			if s == v {
				return true
			}
		}
	}
	return false
}

// in_array 函数实现
func InArrayInt(s interface{}, d []int) bool {
	if len(d) > 0 {
		for _, v := range d {
			if s == v {
				return true
			}
		}
	}
	return false
}

// in_array 函数实现
func InMap(s interface{}, d map[string]string) string {
	if len(d) > 0 {
		for key, v := range d {
			if s == v {
				return key
			}
		}
	}
	return ""
}

// 实现sha1加密
func Sha1(s string) string {
	o := sha1.New()
	o.Write([]byte(s))
	return hex.EncodeToString(o.Sum(nil))

}

// 实现md5加密
func Md5(s string) string {
	//md5密码加密
	Md5_Str := ""
	w := md5.New()
	io.WriteString(w, s)
	Md5_Str = fmt.Sprintf("%x", w.Sum(nil))
	return Md5_Str
}

// 获取分页的偏移量
func GetPageOffset(page, limit, total_row float64) float64 {
	//偏移量计算
	page = (page - 1)
	if page <= 0 {
		page = 0
	}
	total_page := math.Ceil(total_row / limit)
	if page >= total_page {
		page = total_page - 1
	}
	offset := page * limit //计算偏移量
	return offset
}

/**
 * @name: 获取当天格式化后的时间
 * @test: test font
 * @msg:
 * @param {string} layout_str
 * @param {int64} timestamp 0 当前时间
 * @return {string}
 */
func GetTodayFmtStr(layout_str string, timestamp int64) string {
	if timestamp <= 0 {
		//获取当天时间戳
		timestamp = time.Now().Unix()
	}
	//格式化为字符串,tm为Time类型
	tm := time.Unix(timestamp, 0)
	//默认返回的日期格式格式
	if len(layout_str) <= 0 {
		layout_str = "2006-01-02"
	}
	return tm.Format(layout_str)

}

// 指定长度的随机字符串
func CreateRandomString(len int) string {
	var container string
	var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
	b := bytes.NewBufferString(str)
	length := b.Len()
	bigInt := big.NewInt(int64(length))
	for i := 0; i < len; i++ {
		randomInt, _ := rand.Int(rand.Reader, bigInt)
		container += string(str[randomInt.Int64()])
	}
	return container
}

/************** CBC 模式，实现 AES 加解密。*********************/

// PKCS7Padding fills plaintext as an integral multiple of the block length
func PKCS7Padding(p []byte, blockSize int) []byte {
	pad := blockSize - len(p)%blockSize
	padtext := bytes.Repeat([]byte{byte(pad)}, pad)
	return append(p, padtext...)
}

// PKCS7UnPadding removes padding data from the tail of plaintext
func PKCS7UnPadding(p []byte) []byte {
	length := len(p)
	paddLen := int(p[length-1])
	return p[:(length - paddLen)]
}

// AESCBCEncrypt encrypts data with AES algorithm in CBC mode
// Note that key length must be 16, 24 or 32 bytes to select AES-128, AES-192, or AES-256
// Note that AES block size is 16 bytes
func AESCBCEncrypt(p, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	p = PKCS7Padding(p, block.BlockSize())
	ciphertext := make([]byte, len(p))
	blockMode := cipher.NewCBCEncrypter(block, key[:block.BlockSize()])
	blockMode.CryptBlocks(ciphertext, p)
	return ciphertext, nil
}

// AESCBCDecrypt decrypts cipher text with AES algorithm in CBC mode
// Note that key length must be 16, 24 or 32 bytes to select AES-128, AES-192, or AES-256
// Note that AES block size is 16 bytes
func AESCBCDecrypt(c, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	plaintext := make([]byte, len(c))
	blockMode := cipher.NewCBCDecrypter(block, key[:block.BlockSize()])
	blockMode.CryptBlocks(plaintext, c)
	return PKCS7UnPadding(plaintext), err
}

// Base64AESCBCEncrypt encrypts data with AES algorithm in CBC mode and encoded by base64
func Base64AESCBCEncrypt(p, key []byte) (string, error) {
	c, err := AESCBCEncrypt(p, key)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(c), nil
}

// Base64AESCBCDecrypt decrypts cipher text encoded by base64 with AES algorithm in CBC mode
func Base64AESCBCDecrypt(c string, key []byte) ([]byte, error) {
	oriCipher, err := base64.StdEncoding.DecodeString(c)
	if err != nil {
		return nil, err
	}
	p, err := AESCBCDecrypt(oriCipher, key)
	if err != nil {
		return nil, err
	}
	return p, nil
}

/*
	使用示例
	p := []byte("plaintext")
	key := []byte("12345678abcdefgh") //key 16 -->sha128  大于24 -->sha256
	//加密：
	ciphertext, _ := Base64AESCBCEncrypt(p, key)
	fmt.Println(ciphertext)
	//解密：
	plaintext, _ := Base64AESCBCDecrypt(ciphertext, key)
	fmt.Println(string(plaintext))
*/

/************** CBC 模式，实现 AES 加解密 end。*********************/

/**
 * @description: 使用gomail发送邮件
 * @param {[]string} to 收件人
 * @param {*} subject 主题
 * @param {*} body  邮件内容
 * @param {*} serverHost 邮箱服务器地址
 * @param {*} fromEmail 发件人邮箱
 * @param {string} fromPasswd 发件人邮箱密码
 * @param {int} serverPort 邮箱服务器端口
 * @return {*}
 */
func GomailSendToMail(to []string, subject, body, serverHost, fromEmail, fromPasswd string, serverPort int) string {
	// serverHost := "smtp.exmail.qq.com"
	// serverPort := 465
	// fromEmail := "1234@abc.com"
	// fromPasswd := "k35H5d4f52s7T32R"

	if serverHost == "" {
		return "serverHost is null"
	}
	if serverPort <= 0 {
		return "serverPort is err"
	}
	if fromEmail == "" {
		return "fromEmail is null"
	}
	if fromPasswd == "" {
		return "fromPasswd is null"
	}

	//myToers := "li@latelee.org, latelee@163.com" // 逗号隔开
	myToers := ""
	if len(to) > 0 {
		for key, val := range to {
			if val != "" {
				if key == 0 {
					myToers += val
				} else {
					myToers += "," + val
				}
			}
		}
	} else {
		return "Toers is null"
	}
	myCCers := "" //"readchy@163.com"

	// 结构体赋值
	myEmail := &GomailEmailParam{
		ServerHost: serverHost,
		ServerPort: serverPort,
		FromEmail:  fromEmail,
		FromPasswd: fromPasswd,
		Toers:      myToers,
		CCers:      myCCers,
	}
	GomailInitEmail(myEmail)
	errs := GomailSendEmail(subject, body)
	if errs != "success" {
		return errs
	}
	return "ok"
}

/**
 * @description: 判断文件是否存在
 * @param {string} filePath
 * @return {*}
 */
func FileExists(filePath string) bool {
	_, err := os.Open(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}
